]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Merge searchDisplay.js and search.js
authorJasper St. Pierre <jstpierre@mecheye.net>
Tue, 29 Oct 2013 19:49:05 +0000 (15:49 -0400)
committerJasper St. Pierre <jstpierre@mecheye.net>
Tue, 29 Oct 2013 20:02:32 +0000 (16:02 -0400)
search.js used to do a lot more, but now that most of the
functionality has been moved to the remote search system,
it doesn't do a lot. Merge searchDisplay.js into it.

js/Makefile.am
js/ui/search.js
js/ui/searchDisplay.js [deleted file]
js/ui/viewSelector.js
po/POTFILES.in

index 4fdbae8aae1d1a8cb29cbd7792cdd06d925e69b1..677af78959f9aa14f71839a1302a09c2478a0748 100644 (file)
@@ -90,7 +90,6 @@ nobase_dist_js_DATA =         \
         ui/screenShield.js     \
        ui/scripting.js         \
        ui/search.js            \
-       ui/searchDisplay.js     \
        ui/shellDBus.js         \
        ui/status/accessibility.js      \
        ui/status/brightness.js \
index 3648fa130a1c5b32c6b124e31347624742c6f78e..1ee9471edf64249aa23e1f20b1ccd7da74a093a6 100644 (file)
@@ -1,10 +1,26 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
+const Clutter = imports.gi.Clutter;
 const Lang = imports.lang;
+const Gtk = imports.gi.Gtk;
+const Meta = imports.gi.Meta;
 const Signals = imports.signals;
+const St = imports.gi.St;
+const Atk = imports.gi.Atk;
+
+const DND = imports.ui.dnd;
+const IconGrid = imports.ui.iconGrid;
+const Main = imports.ui.main;
+const Overview = imports.ui.overview;
+const Separator = imports.ui.separator;
+const Search = imports.ui.search;
+const Util = imports.misc.util;
 
 const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
 
+const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
+const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
+
 const SearchSystem = new Lang.Class({
     Name: 'SearchSystem',
 
@@ -95,3 +111,550 @@ const SearchSystem = new Lang.Class({
     }
 });
 Signals.addSignalMethods(SearchSystem.prototype);
+
+const MaxWidthBin = new Lang.Class({
+    Name: 'MaxWidthBin',
+    Extends: St.Bin,
+
+    vfunc_allocate: function(box, flags) {
+        let themeNode = this.get_theme_node();
+        let maxWidth = themeNode.get_max_width();
+        let availWidth = box.x2 - box.x1;
+        let adjustedBox = box;
+
+        if (availWidth > maxWidth) {
+            let excessWidth = availWidth - maxWidth;
+            adjustedBox.x1 += Math.floor(excessWidth / 2);
+            adjustedBox.x2 -= Math.floor(excessWidth / 2);
+        }
+
+        this.parent(adjustedBox, flags);
+    }
+});
+
+const SearchResult = new Lang.Class({
+    Name: 'SearchResult',
+
+    _init: function(provider, metaInfo, terms) {
+        this.provider = provider;
+        this.metaInfo = metaInfo;
+        this.terms = terms;
+
+        this.actor = new St.Button({ reactive: true,
+                                     can_focus: true,
+                                     track_hover: true,
+                                     x_align: St.Align.START,
+                                     y_fill: true });
+
+        this.actor._delegate = this;
+        this.actor.connect('clicked', Lang.bind(this, this.activate));
+    },
+
+    activate: function() {
+        this.provider.activateResult(this.metaInfo.id, this.terms);
+        Main.overview.toggle();
+    },
+
+    setSelected: function(selected) {
+        if (selected)
+            this.actor.add_style_pseudo_class('selected');
+        else
+            this.actor.remove_style_pseudo_class('selected');
+    }
+});
+
+const ListSearchResult = new Lang.Class({
+    Name: 'ListSearchResult',
+    Extends: SearchResult,
+
+    ICON_SIZE: 64,
+
+    _init: function(provider, metaInfo, terms) {
+        this.parent(provider, metaInfo, terms);
+
+        this.actor.style_class = 'list-search-result';
+        this.actor.x_fill = true;
+
+        let content = new St.BoxLayout({ style_class: 'list-search-result-content',
+                                         vertical: false });
+        this.actor.set_child(content);
+
+        // An icon for, or thumbnail of, content
+        let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
+        if (icon) {
+            content.add(icon);
+        }
+
+        let details = new St.BoxLayout({ vertical: true });
+        content.add(details, { x_fill: true,
+                               y_fill: false,
+                               x_align: St.Align.START,
+                               y_align: St.Align.MIDDLE });
+
+        let title = new St.Label({ style_class: 'list-search-result-title',
+                                   text: this.metaInfo['name'] })
+        details.add(title, { x_fill: false,
+                             y_fill: false,
+                             x_align: St.Align.START,
+                             y_align: St.Align.START });
+        this.actor.label_actor = title;
+
+        if (this.metaInfo['description']) {
+            let description = new St.Label({ style_class: 'list-search-result-description' });
+            description.clutter_text.set_markup(this.metaInfo['description']);
+            details.add(description, { x_fill: false,
+                                       y_fill: false,
+                                       x_align: St.Align.START,
+                                       y_align: St.Align.END });
+        }
+    }
+});
+
+const GridSearchResult = new Lang.Class({
+    Name: 'GridSearchResult',
+    Extends: SearchResult,
+
+    _init: function(provider, metaInfo, terms) {
+        this.parent(provider, metaInfo, terms);
+
+        this.actor.style_class = 'grid-search-result';
+
+        let content = provider.createResultObject(metaInfo, terms);
+        let dragSource = null;
+
+        if (content == null) {
+            let actor = new St.Bin();
+            let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
+                                             { createIcon: this.metaInfo['createIcon'] });
+            actor.set_child(icon.actor);
+            actor.label_actor = icon.label;
+            dragSource = icon.icon;
+            content = { actor: actor, icon: icon };
+        } else {
+            if (content._delegate && content._delegate.getDragActorSource)
+                dragSource = content._delegate.getDragActorSource();
+        }
+
+        this.actor.set_child(content.actor);
+        this.actor.label_actor = content.actor.label_actor;
+        this.icon = content.icon;
+
+        let draggable = DND.makeDraggable(this.actor);
+        draggable.connect('drag-begin',
+                          Lang.bind(this, function() {
+                              Main.overview.beginItemDrag(this);
+                          }));
+        draggable.connect('drag-cancelled',
+                          Lang.bind(this, function() {
+                              Main.overview.cancelledItemDrag(this);
+                          }));
+        draggable.connect('drag-end',
+                          Lang.bind(this, function() {
+                              Main.overview.endItemDrag(this);
+                          }));
+
+        if (!dragSource)
+            // not exactly right, but alignment problems are hard to notice
+            dragSource = content;
+        this._dragActorSource = dragSource;
+    },
+
+    getDragActorSource: function() {
+        return this._dragActorSource;
+    },
+
+    getDragActor: function() {
+        return this.metaInfo['createIcon'](Main.overview.dashIconSize);
+    },
+
+    shellWorkspaceLaunch: function(params) {
+        if (this.provider.dragActivateResult)
+            this.provider.dragActivateResult(this.metaInfo.id, params);
+        else
+            this.provider.activateResult(this.metaInfo.id, this.terms);
+    }
+});
+
+const SearchResultsBase = new Lang.Class({
+    Name: 'SearchResultsBase',
+
+    _init: function(provider) {
+        this.provider = provider;
+
+        this._terms = [];
+
+        this.actor = new St.BoxLayout({ style_class: 'search-section',
+                                        vertical: true });
+
+        this._resultDisplayBin = new St.Bin({ x_fill: true,
+                                              y_fill: true });
+        this.actor.add(this._resultDisplayBin, { expand: true });
+
+        let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
+        this.actor.add(separator.actor);
+    },
+
+    destroy: function() {
+        this.actor.destroy();
+        this._terms = [];
+    },
+
+    _clearResultDisplay: function() {
+    },
+
+    clear: function() {
+        this._clearResultDisplay();
+        this.actor.hide();
+    },
+
+    _keyFocusIn: function(actor) {
+        this.emit('key-focus-in', actor);
+    },
+
+    _setMoreIconVisible: function(visible) {
+    },
+
+    updateSearch: function(providerResults, terms, callback) {
+        this._terms = terms;
+
+        if (providerResults.length == 0) {
+            this._clearResultDisplay();
+            this.actor.hide();
+            callback();
+        } else {
+            let maxResults = this._getMaxDisplayedResults();
+            let results = this.provider.filterResults(providerResults, maxResults);
+            let hasMoreResults = results.length < providerResults.length;
+
+            this.provider.getResultMetas(results, Lang.bind(this, function(metas) {
+                this.clear();
+
+                // To avoid CSS transitions causing flickering when
+                // the first search result stays the same, we hide the
+                // content while filling in the results.
+                this.actor.hide();
+                this._clearResultDisplay();
+                this._renderResults(metas);
+                this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
+                this.actor.show();
+                callback();
+            }));
+        }
+    }
+});
+
+const ListSearchResults = new Lang.Class({
+    Name: 'ListSearchResults',
+    Extends: SearchResultsBase,
+
+    _init: function(provider) {
+        this.parent(provider);
+
+        this._container = new St.BoxLayout({ style_class: 'search-section-content' });
+        this.providerIcon = new ProviderIcon(provider);
+        this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
+        this.providerIcon.connect('clicked', Lang.bind(this,
+            function() {
+                provider.launchSearch(this._terms);
+                Main.overview.toggle();
+            }));
+
+        this._container.add(this.providerIcon, { x_fill: false,
+                                                 y_fill: false,
+                                                 x_align: St.Align.START,
+                                                 y_align: St.Align.START });
+
+        this._content = new St.BoxLayout({ style_class: 'list-search-results',
+                                           vertical: true });
+        this._container.add(this._content, { expand: true });
+
+        this._resultDisplayBin.set_child(this._container);
+    },
+
+    _setMoreIconVisible: function(visible) {
+        this.providerIcon.moreIcon.visible = true;
+    },
+
+    _getMaxDisplayedResults: function() {
+        return MAX_LIST_SEARCH_RESULTS_ROWS;
+    },
+
+    _renderResults: function(metas) {
+        for (let i = 0; i < metas.length; i++) {
+            let display = new ListSearchResult(this.provider, metas[i], this._terms);
+            display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
+            this._content.add_actor(display.actor);
+        }
+    },
+
+    _clearResultDisplay: function () {
+        this._content.destroy_all_children();
+    },
+
+    getFirstResult: function() {
+        if (this._content.get_n_children() > 0)
+            return this._content.get_child_at_index(0)._delegate;
+        else
+            return null;
+    }
+});
+Signals.addSignalMethods(ListSearchResults.prototype);
+
+const GridSearchResults = new Lang.Class({
+    Name: 'GridSearchResults',
+    Extends: SearchResultsBase,
+
+    _init: function(provider) {
+        this.parent(provider);
+
+        this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
+                                             xAlign: St.Align.START });
+        this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
+        this._bin.set_child(this._grid.actor);
+
+        this._resultDisplayBin.set_child(this._bin);
+    },
+
+    _getMaxDisplayedResults: function() {
+        return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
+    },
+
+    _renderResults: function(metas) {
+        for (let i = 0; i < metas.length; i++) {
+            let display = new GridSearchResult(this.provider, metas[i], this._terms);
+            display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
+            this._grid.addItem(display);
+        }
+    },
+
+    _clearResultDisplay: function () {
+        this._grid.removeAll();
+    },
+
+    getFirstResult: function() {
+        if (this._grid.visibleItemsCount() > 0)
+            return this._grid.getItemAtIndex(0)._delegate;
+        else
+            return null;
+    }
+});
+Signals.addSignalMethods(GridSearchResults.prototype);
+
+const SearchResults = new Lang.Class({
+    Name: 'SearchResults',
+
+    _init: function(searchSystem) {
+        this._searchSystem = searchSystem;
+        this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
+
+        this.actor = new St.BoxLayout({ name: 'searchResults',
+                                        vertical: true });
+
+        this._content = new St.BoxLayout({ name: 'searchResultsContent',
+                                           vertical: true });
+        this._contentBin = new MaxWidthBin({ name: 'searchResultsBin',
+                                             x_fill: true,
+                                             y_fill: true,
+                                             child: this._content });
+
+        let scrollChild = new St.BoxLayout();
+        scrollChild.add(this._contentBin, { expand: true });
+
+        this._scrollView = new St.ScrollView({ x_fill: true,
+                                               y_fill: false,
+                                               overlay_scrollbars: true,
+                                               style_class: 'search-display vfade' });
+        this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+        this._scrollView.add_actor(scrollChild);
+        let action = new Clutter.PanAction({ interpolate: true });
+        action.connect('pan', Lang.bind(this, this._onPan));
+        this._scrollView.add_action(action);
+
+        this.actor.add(this._scrollView, { x_fill: true,
+                                           y_fill: true,
+                                           expand: true,
+                                           x_align: St.Align.START,
+                                           y_align: St.Align.START });
+
+        this._statusText = new St.Label({ style_class: 'search-statustext' });
+        this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
+                                       y_align: St.Align.MIDDLE });
+        this._content.add(this._statusBin, { expand: true });
+        this._statusBin.add_actor(this._statusText);
+        this._providers = this._searchSystem.getProviders();
+        this._providerDisplays = {};
+        for (let i = 0; i < this._providers.length; i++) {
+            this.createProviderDisplay(this._providers[i]);
+        }
+
+        this._highlightDefault = false;
+        this._defaultResult = null;
+    },
+
+    _onPan: function(action) {
+        let [dist, dx, dy] = action.get_motion_delta(0);
+        let adjustment = this._scrollView.vscroll.adjustment;
+        adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
+        return false;
+    },
+
+    _keyFocusIn: function(provider, actor) {
+        Util.ensureActorVisibleInScrollView(this._scrollView, actor);
+    },
+
+    createProviderDisplay: function(provider) {
+        let providerDisplay = null;
+
+        if (provider.appInfo) {
+            providerDisplay = new ListSearchResults(provider);
+        } else {
+            providerDisplay = new GridSearchResults(provider);
+        }
+
+        providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
+        this._providerDisplays[provider.id] = providerDisplay;
+        this._content.add(providerDisplay.actor);
+    },
+
+    destroyProviderDisplay: function(provider) {
+        this._providerDisplays[provider.id].destroy();
+        delete this._providerDisplays[provider.id];
+    },
+
+    _clearDisplay: function() {
+        for (let i = 0; i < this._providers.length; i++) {
+            let provider = this._providers[i];
+            let providerDisplay = this._providerDisplays[provider.id];
+            providerDisplay.clear();
+        }
+    },
+
+    reset: function() {
+        this._searchSystem.reset();
+        this._statusBin.hide();
+        this._clearDisplay();
+        this._defaultResult = null;
+    },
+
+    startingSearch: function() {
+        this.reset();
+        this._statusText.set_text(_("Searching…"));
+        this._statusBin.show();
+    },
+
+    _maybeSetInitialSelection: function() {
+        let newDefaultResult = null;
+
+        for (let i = 0; i < this._providers.length; i++) {
+            let provider = this._providers[i];
+            let display = this._providerDisplays[provider.id];
+
+            if (!display.actor.visible)
+                continue;
+
+            let firstResult = display.getFirstResult();
+            if (firstResult) {
+                newDefaultResult = firstResult;
+                break; // select this one!
+            }
+        }
+
+        if (newDefaultResult != this._defaultResult) {
+            if (this._defaultResult)
+                this._defaultResult.setSelected(false);
+            if (newDefaultResult)
+                newDefaultResult.setSelected(this._highlightDefault);
+
+            this._defaultResult = newDefaultResult;
+        }
+    },
+
+    _updateStatusText: function () {
+        let haveResults = false;
+
+        for (let i = 0; i < this._providers.length; i++) {
+            let provider = this._providers[i];
+            let display = this._providerDisplays[provider.id];
+            if (display.getFirstResult()) {
+                haveResults = true;
+                break;
+            }
+        }
+
+        if (!haveResults) {
+            this._statusText.set_text(_("No results."));
+            this._statusBin.show();
+        } else {
+            this._statusBin.hide();
+        }
+    },
+
+    _updateResults: function(searchSystem, results) {
+        let terms = searchSystem.getTerms();
+        let [provider, providerResults] = results;
+        let display = this._providerDisplays[provider.id];
+
+        display.updateSearch(providerResults, terms, Lang.bind(this, function() {
+            this._maybeSetInitialSelection();
+            this._updateStatusText();
+        }));
+    },
+
+    activateDefault: function() {
+        if (this._defaultResult)
+            this._defaultResult.activate();
+    },
+
+    highlightDefault: function(highlight) {
+        this._highlightDefault = highlight;
+        if (this._defaultResult)
+            this._defaultResult.setSelected(highlight);
+    },
+
+    navigateFocus: function(direction) {
+        let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
+        if (direction == Gtk.DirectionType.TAB_BACKWARD ||
+            direction == (rtl ? Gtk.DirectionType.RIGHT
+                              : Gtk.DirectionType.LEFT) ||
+            direction == Gtk.DirectionType.UP) {
+            this.actor.navigate_focus(null, direction, false);
+            return;
+        }
+
+        let from = this._defaultResult ? this._defaultResult.actor : null;
+        this.actor.navigate_focus(from, direction, false);
+    }
+});
+
+const ProviderIcon = new Lang.Class({
+    Name: 'ProviderIcon',
+    Extends: St.Button,
+
+    PROVIDER_ICON_SIZE: 48,
+
+    _init: function(provider) {
+        this.provider = provider;
+        this.parent({ style_class: 'search-provider-icon',
+                      reactive: true,
+                      can_focus: true,
+                      accessible_name: provider.appInfo.get_name(),
+                      track_hover: true });
+
+        this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
+        this.set_child(this._content);
+
+        let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
+
+        this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
+                                        visible: false,
+                                        x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
+                                        y_align: Clutter.ActorAlign.END,
+                                        x_expand: true,
+                                        y_expand: true });
+
+        let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
+                                 gicon: provider.appInfo.get_icon() });
+        this._content.add_actor(icon);
+        this._content.add_actor(this.moreIcon);
+    }
+});
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
deleted file mode 100644 (file)
index 8ae97ab..0000000
+++ /dev/null
@@ -1,567 +0,0 @@
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-
-const Clutter = imports.gi.Clutter;
-const Lang = imports.lang;
-const Gtk = imports.gi.Gtk;
-const Meta = imports.gi.Meta;
-const Signals = imports.signals;
-const St = imports.gi.St;
-const Atk = imports.gi.Atk;
-
-const DND = imports.ui.dnd;
-const IconGrid = imports.ui.iconGrid;
-const Main = imports.ui.main;
-const Overview = imports.ui.overview;
-const Separator = imports.ui.separator;
-const Search = imports.ui.search;
-const Util = imports.misc.util;
-
-const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
-const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
-
-const MaxWidthBin = new Lang.Class({
-    Name: 'MaxWidthBin',
-    Extends: St.Bin,
-
-    vfunc_allocate: function(box, flags) {
-        let themeNode = this.get_theme_node();
-        let maxWidth = themeNode.get_max_width();
-        let availWidth = box.x2 - box.x1;
-        let adjustedBox = box;
-
-        if (availWidth > maxWidth) {
-            let excessWidth = availWidth - maxWidth;
-            adjustedBox.x1 += Math.floor(excessWidth / 2);
-            adjustedBox.x2 -= Math.floor(excessWidth / 2);
-        }
-
-        this.parent(adjustedBox, flags);
-    }
-});
-
-const SearchResult = new Lang.Class({
-    Name: 'SearchResult',
-
-    _init: function(provider, metaInfo, terms) {
-        this.provider = provider;
-        this.metaInfo = metaInfo;
-        this.terms = terms;
-
-        this.actor = new St.Button({ reactive: true,
-                                     can_focus: true,
-                                     track_hover: true,
-                                     x_align: St.Align.START,
-                                     y_fill: true });
-
-        this.actor._delegate = this;
-        this.actor.connect('clicked', Lang.bind(this, this.activate));
-    },
-
-    activate: function() {
-        this.provider.activateResult(this.metaInfo.id, this.terms);
-        Main.overview.toggle();
-    },
-
-    setSelected: function(selected) {
-        if (selected)
-            this.actor.add_style_pseudo_class('selected');
-        else
-            this.actor.remove_style_pseudo_class('selected');
-    }
-});
-
-const ListSearchResult = new Lang.Class({
-    Name: 'ListSearchResult',
-    Extends: SearchResult,
-
-    ICON_SIZE: 64,
-
-    _init: function(provider, metaInfo, terms) {
-        this.parent(provider, metaInfo, terms);
-
-        this.actor.style_class = 'list-search-result';
-        this.actor.x_fill = true;
-
-        let content = new St.BoxLayout({ style_class: 'list-search-result-content',
-                                         vertical: false });
-        this.actor.set_child(content);
-
-        // An icon for, or thumbnail of, content
-        let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
-        if (icon) {
-            content.add(icon);
-        }
-
-        let details = new St.BoxLayout({ vertical: true });
-        content.add(details, { x_fill: true,
-                               y_fill: false,
-                               x_align: St.Align.START,
-                               y_align: St.Align.MIDDLE });
-
-        let title = new St.Label({ style_class: 'list-search-result-title',
-                                   text: this.metaInfo['name'] })
-        details.add(title, { x_fill: false,
-                             y_fill: false,
-                             x_align: St.Align.START,
-                             y_align: St.Align.START });
-        this.actor.label_actor = title;
-
-        if (this.metaInfo['description']) {
-            let description = new St.Label({ style_class: 'list-search-result-description' });
-            description.clutter_text.set_markup(this.metaInfo['description']);
-            details.add(description, { x_fill: false,
-                                       y_fill: false,
-                                       x_align: St.Align.START,
-                                       y_align: St.Align.END });
-        }
-    }
-});
-
-const GridSearchResult = new Lang.Class({
-    Name: 'GridSearchResult',
-    Extends: SearchResult,
-
-    _init: function(provider, metaInfo, terms) {
-        this.parent(provider, metaInfo, terms);
-
-        this.actor.style_class = 'grid-search-result';
-
-        let content = provider.createResultObject(metaInfo, terms);
-        let dragSource = null;
-
-        if (content == null) {
-            let actor = new St.Bin();
-            let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
-                                             { createIcon: this.metaInfo['createIcon'] });
-            actor.set_child(icon.actor);
-            actor.label_actor = icon.label;
-            dragSource = icon.icon;
-            content = { actor: actor, icon: icon };
-        } else {
-            if (content._delegate && content._delegate.getDragActorSource)
-                dragSource = content._delegate.getDragActorSource();
-        }
-
-        this.actor.set_child(content.actor);
-        this.actor.label_actor = content.actor.label_actor;
-        this.icon = content.icon;
-
-        let draggable = DND.makeDraggable(this.actor);
-        draggable.connect('drag-begin',
-                          Lang.bind(this, function() {
-                              Main.overview.beginItemDrag(this);
-                          }));
-        draggable.connect('drag-cancelled',
-                          Lang.bind(this, function() {
-                              Main.overview.cancelledItemDrag(this);
-                          }));
-        draggable.connect('drag-end',
-                          Lang.bind(this, function() {
-                              Main.overview.endItemDrag(this);
-                          }));
-
-        if (!dragSource)
-            // not exactly right, but alignment problems are hard to notice
-            dragSource = content;
-        this._dragActorSource = dragSource;
-    },
-
-    getDragActorSource: function() {
-        return this._dragActorSource;
-    },
-
-    getDragActor: function() {
-        return this.metaInfo['createIcon'](Main.overview.dashIconSize);
-    },
-
-    shellWorkspaceLaunch: function(params) {
-        if (this.provider.dragActivateResult)
-            this.provider.dragActivateResult(this.metaInfo.id, params);
-        else
-            this.provider.activateResult(this.metaInfo.id, this.terms);
-    }
-});
-
-const SearchResultsBase = new Lang.Class({
-    Name: 'SearchResultsBase',
-
-    _init: function(provider) {
-        this.provider = provider;
-
-        this._terms = [];
-
-        this.actor = new St.BoxLayout({ style_class: 'search-section',
-                                        vertical: true });
-
-        this._resultDisplayBin = new St.Bin({ x_fill: true,
-                                              y_fill: true });
-        this.actor.add(this._resultDisplayBin, { expand: true });
-
-        let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
-        this.actor.add(separator.actor);
-    },
-
-    destroy: function() {
-        this.actor.destroy();
-        this._terms = [];
-    },
-
-    _clearResultDisplay: function() {
-    },
-
-    clear: function() {
-        this._clearResultDisplay();
-        this.actor.hide();
-    },
-
-    _keyFocusIn: function(actor) {
-        this.emit('key-focus-in', actor);
-    },
-
-    _setMoreIconVisible: function(visible) {
-    },
-
-    updateSearch: function(providerResults, terms, callback) {
-        this._terms = terms;
-
-        if (providerResults.length == 0) {
-            this._clearResultDisplay();
-            this.actor.hide();
-            callback();
-        } else {
-            let maxResults = this._getMaxDisplayedResults();
-            let results = this.provider.filterResults(providerResults, maxResults);
-            let hasMoreResults = results.length < providerResults.length;
-
-            this.provider.getResultMetas(results, Lang.bind(this, function(metas) {
-                this.clear();
-
-                // To avoid CSS transitions causing flickering when
-                // the first search result stays the same, we hide the
-                // content while filling in the results.
-                this.actor.hide();
-                this._clearResultDisplay();
-                this._renderResults(metas);
-                this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
-                this.actor.show();
-                callback();
-            }));
-        }
-    }
-});
-
-const ListSearchResults = new Lang.Class({
-    Name: 'ListSearchResults',
-    Extends: SearchResultsBase,
-
-    _init: function(provider) {
-        this.parent(provider);
-
-        this._container = new St.BoxLayout({ style_class: 'search-section-content' });
-        this.providerIcon = new ProviderIcon(provider);
-        this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
-        this.providerIcon.connect('clicked', Lang.bind(this,
-            function() {
-                provider.launchSearch(this._terms);
-                Main.overview.toggle();
-            }));
-
-        this._container.add(this.providerIcon, { x_fill: false,
-                                                 y_fill: false,
-                                                 x_align: St.Align.START,
-                                                 y_align: St.Align.START });
-
-        this._content = new St.BoxLayout({ style_class: 'list-search-results',
-                                           vertical: true });
-        this._container.add(this._content, { expand: true });
-
-        this._resultDisplayBin.set_child(this._container);
-    },
-
-    _setMoreIconVisible: function(visible) {
-        this.providerIcon.moreIcon.visible = true;
-    },
-
-    _getMaxDisplayedResults: function() {
-        return MAX_LIST_SEARCH_RESULTS_ROWS;
-    },
-
-    _renderResults: function(metas) {
-        for (let i = 0; i < metas.length; i++) {
-            let display = new ListSearchResult(this.provider, metas[i], this._terms);
-            display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
-            this._content.add_actor(display.actor);
-        }
-    },
-
-    _clearResultDisplay: function () {
-        this._content.destroy_all_children();
-    },
-
-    getFirstResult: function() {
-        if (this._content.get_n_children() > 0)
-            return this._content.get_child_at_index(0)._delegate;
-        else
-            return null;
-    }
-});
-Signals.addSignalMethods(ListSearchResults.prototype);
-
-const GridSearchResults = new Lang.Class({
-    Name: 'GridSearchResults',
-    Extends: SearchResultsBase,
-
-    _init: function(provider) {
-        this.parent(provider);
-
-        this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
-                                             xAlign: St.Align.START });
-        this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
-        this._bin.set_child(this._grid.actor);
-
-        this._resultDisplayBin.set_child(this._bin);
-    },
-
-    _getMaxDisplayedResults: function() {
-        return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
-    },
-
-    _renderResults: function(metas) {
-        for (let i = 0; i < metas.length; i++) {
-            let display = new GridSearchResult(this.provider, metas[i], this._terms);
-            display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
-            this._grid.addItem(display);
-        }
-    },
-
-    _clearResultDisplay: function () {
-        this._grid.removeAll();
-    },
-
-    getFirstResult: function() {
-        if (this._grid.visibleItemsCount() > 0)
-            return this._grid.getItemAtIndex(0)._delegate;
-        else
-            return null;
-    }
-});
-Signals.addSignalMethods(GridSearchResults.prototype);
-
-const SearchResults = new Lang.Class({
-    Name: 'SearchResults',
-
-    _init: function(searchSystem) {
-        this._searchSystem = searchSystem;
-        this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
-
-        this.actor = new St.BoxLayout({ name: 'searchResults',
-                                        vertical: true });
-
-        this._content = new St.BoxLayout({ name: 'searchResultsContent',
-                                           vertical: true });
-        this._contentBin = new MaxWidthBin({ name: 'searchResultsBin',
-                                             x_fill: true,
-                                             y_fill: true,
-                                             child: this._content });
-
-        let scrollChild = new St.BoxLayout();
-        scrollChild.add(this._contentBin, { expand: true });
-
-        this._scrollView = new St.ScrollView({ x_fill: true,
-                                               y_fill: false,
-                                               overlay_scrollbars: true,
-                                               style_class: 'search-display vfade' });
-        this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
-        this._scrollView.add_actor(scrollChild);
-        let action = new Clutter.PanAction({ interpolate: true });
-        action.connect('pan', Lang.bind(this, this._onPan));
-        this._scrollView.add_action(action);
-
-        this.actor.add(this._scrollView, { x_fill: true,
-                                           y_fill: true,
-                                           expand: true,
-                                           x_align: St.Align.START,
-                                           y_align: St.Align.START });
-
-        this._statusText = new St.Label({ style_class: 'search-statustext' });
-        this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
-                                       y_align: St.Align.MIDDLE });
-        this._content.add(this._statusBin, { expand: true });
-        this._statusBin.add_actor(this._statusText);
-        this._providers = this._searchSystem.getProviders();
-        this._providerDisplays = {};
-        for (let i = 0; i < this._providers.length; i++) {
-            this.createProviderDisplay(this._providers[i]);
-        }
-
-        this._highlightDefault = false;
-        this._defaultResult = null;
-    },
-
-    _onPan: function(action) {
-        let [dist, dx, dy] = action.get_motion_delta(0);
-        let adjustment = this._scrollView.vscroll.adjustment;
-        adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
-        return false;
-    },
-
-    _keyFocusIn: function(provider, actor) {
-        Util.ensureActorVisibleInScrollView(this._scrollView, actor);
-    },
-
-    createProviderDisplay: function(provider) {
-        let providerDisplay = null;
-
-        if (provider.appInfo) {
-            providerDisplay = new ListSearchResults(provider);
-        } else {
-            providerDisplay = new GridSearchResults(provider);
-        }
-
-        providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
-        this._providerDisplays[provider.id] = providerDisplay;
-        this._content.add(providerDisplay.actor);
-    },
-
-    destroyProviderDisplay: function(provider) {
-        this._providerDisplays[provider.id].destroy();
-        delete this._providerDisplays[provider.id];
-    },
-
-    _clearDisplay: function() {
-        for (let i = 0; i < this._providers.length; i++) {
-            let provider = this._providers[i];
-            let providerDisplay = this._providerDisplays[provider.id];
-            providerDisplay.clear();
-        }
-    },
-
-    reset: function() {
-        this._searchSystem.reset();
-        this._statusBin.hide();
-        this._clearDisplay();
-        this._defaultResult = null;
-    },
-
-    startingSearch: function() {
-        this.reset();
-        this._statusText.set_text(_("Searching…"));
-        this._statusBin.show();
-    },
-
-    _maybeSetInitialSelection: function() {
-        let newDefaultResult = null;
-
-        for (let i = 0; i < this._providers.length; i++) {
-            let provider = this._providers[i];
-            let display = this._providerDisplays[provider.id];
-
-            if (!display.actor.visible)
-                continue;
-
-            let firstResult = display.getFirstResult();
-            if (firstResult) {
-                newDefaultResult = firstResult;
-                break; // select this one!
-            }
-        }
-
-        if (newDefaultResult != this._defaultResult) {
-            if (this._defaultResult)
-                this._defaultResult.setSelected(false);
-            if (newDefaultResult)
-                newDefaultResult.setSelected(this._highlightDefault);
-
-            this._defaultResult = newDefaultResult;
-        }
-    },
-
-    _updateStatusText: function () {
-        let haveResults = false;
-
-        for (let i = 0; i < this._providers.length; i++) {
-            let provider = this._providers[i];
-            let display = this._providerDisplays[provider.id];
-            if (display.getFirstResult()) {
-                haveResults = true;
-                break;
-            }
-        }
-
-        if (!haveResults) {
-            this._statusText.set_text(_("No results."));
-            this._statusBin.show();
-        } else {
-            this._statusBin.hide();
-        }
-    },
-
-    _updateResults: function(searchSystem, results) {
-        let terms = searchSystem.getTerms();
-        let [provider, providerResults] = results;
-        let display = this._providerDisplays[provider.id];
-
-        display.updateSearch(providerResults, terms, Lang.bind(this, function() {
-            this._maybeSetInitialSelection();
-            this._updateStatusText();
-        }));
-    },
-
-    activateDefault: function() {
-        if (this._defaultResult)
-            this._defaultResult.activate();
-    },
-
-    highlightDefault: function(highlight) {
-        this._highlightDefault = highlight;
-        if (this._defaultResult)
-            this._defaultResult.setSelected(highlight);
-    },
-
-    navigateFocus: function(direction) {
-        let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
-        if (direction == Gtk.DirectionType.TAB_BACKWARD ||
-            direction == (rtl ? Gtk.DirectionType.RIGHT
-                              : Gtk.DirectionType.LEFT) ||
-            direction == Gtk.DirectionType.UP) {
-            this.actor.navigate_focus(null, direction, false);
-            return;
-        }
-
-        let from = this._defaultResult ? this._defaultResult.actor : null;
-        this.actor.navigate_focus(from, direction, false);
-    }
-});
-
-const ProviderIcon = new Lang.Class({
-    Name: 'ProviderIcon',
-    Extends: St.Button,
-
-    PROVIDER_ICON_SIZE: 48,
-
-    _init: function(provider) {
-        this.provider = provider;
-        this.parent({ style_class: 'search-provider-icon',
-                      reactive: true,
-                      can_focus: true,
-                      accessible_name: provider.appInfo.get_name(),
-                      track_hover: true });
-
-        this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
-        this.set_child(this._content);
-
-        let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
-
-        this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
-                                        visible: false,
-                                        x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
-                                        y_align: Clutter.ActorAlign.END,
-                                        x_expand: true,
-                                        y_expand: true });
-
-        let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
-                                 gicon: provider.appInfo.get_icon() });
-        this._content.add_actor(icon);
-        this._content.add_actor(this.moreIcon);
-    }
-});
index 9e86288ec522ae3728251a028f6c2b3df408a5bf..3c9cf2131cc7291f241179578dc7f98e96744156 100644 (file)
@@ -16,7 +16,6 @@ const OverviewControls = imports.ui.overviewControls;
 const Params = imports.misc.params;
 const RemoteSearch = imports.ui.remoteSearch;
 const Search = imports.ui.search;
-const SearchDisplay = imports.ui.searchDisplay;
 const ShellEntry = imports.ui.shellEntry;
 const Tweener = imports.ui.tweener;
 const WorkspacesView = imports.ui.workspacesView;
@@ -102,7 +101,7 @@ const ViewSelector = new Lang.Class({
         this._appsPage = this._addPage(this.appDisplay.actor,
                                        _("Applications"), 'view-grid-symbolic');
 
-        this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
+        this._searchResults = new Search.SearchResults(this._searchSystem);
         this._searchPage = this._addPage(this._searchResults.actor,
                                          _("Search"), 'edit-find-symbolic',
                                          { a11yFocus: this._entry });
index 6ec28e757c38c05f77376b5e4df5bc99596c5cb7..3113662dcd1935599f24dcf0099fb2567bf2b450 100644 (file)
@@ -38,7 +38,7 @@ js/ui/panel.js
 js/ui/popupMenu.js
 js/ui/runDialog.js
 js/ui/screenShield.js
-js/ui/searchDisplay.js
+js/ui/search.js
 js/ui/shellEntry.js
 js/ui/shellMountOperation.js
 js/ui/status/accessibility.js